﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Linq.Mapping;
using System.Reflection;
using System.Data.Linq;
namespace DataLayer
{
    public class LinqMappingHelper
    {
        MetaModel _dataContextMapping;
        public LinqMappingHelper(MetaModel dataContextMapping)
        {
            _dataContextMapping = dataContextMapping;
        }
        #region Primary Key
        public string GetPrimaryKeyName(Type entityType)
        {
            MetaTable mapping = _dataContextMapping.GetTable(entityType);
            int count = mapping.RowType.DataMembers.Count(d => d.IsPrimaryKey);
            if (count < 1) throw new Exception(String.Format("Table {0} does not contain a Primary Key field", mapping.TableName));
            if (count > 1) throw new Exception(String.Format("Table {0} contains a composite primary key field", mapping.TableName));

            MetaDataMember primaryKey = mapping.RowType.DataMembers.SingleOrDefault(d => d.IsPrimaryKey);

            return primaryKey.MappedName;
        }
        public PropertyInfo GetPrimaryKey(Type entityType)
        {
            return entityType.GetProperty(GetPrimaryKeyName(entityType));
        }

        public object GetPrimaryKeyValue(object entity)
        {
            return GetPrimaryKey(entity.GetType()).GetValue(entity, null);
        }
        public T GetEntityByPrimaryKeyValue<T>(EntitySet<T> entitySet, object value) where T : class, new()
        {
            T entity = entitySet.FirstOrDefault(x => GetPrimaryKeyValue(x).Equals(value));
            return entity;
        }
        #endregion

        #region Properties
        protected IEnumerable<MetaDataMember> GetPropertiesMetaData(Type entityType, Func<MetaDataMember, bool> predicate)
        {
            MetaTable mapping = _dataContextMapping.GetTable(entityType);
            return mapping.RowType.DataMembers.Where(predicate);
        }
        public IEnumerable<MetaDataMember> GetDatabasePropertiesMetaData(Type entityType)
        {
            return GetPropertiesMetaData(entityType, x => x.DbType != null);
        }
        public IEnumerable<MetaDataMember> GetAssociationPropertiesMetaData(Type entityType)
        {
            return GetPropertiesMetaData(entityType, x => x.Association != null && x.Association.IsMany && x.Association.ThisKeyIsPrimaryKey);
        }
        public PropertyInfo GetPropertyInfoFromMetaData(Type entityType, MetaDataMember m)
        {
            return entityType.GetProperty(m.Name);
        }
        protected List<PropertyInfo> GetProperties(Type entityType, Func<MetaDataMember, bool> predicate)
        {
            var databaseProperties = new List<PropertyInfo>();
            foreach (MetaDataMember dm in GetPropertiesMetaData(entityType, predicate))
            {
                databaseProperties.Add(entityType.GetProperty(dm.Name));
            }
            return databaseProperties;
        }
        public List<PropertyInfo> GetDatabaseProperties(Type entityType)
        {
            return GetProperties(entityType, x => x.DbType != null);
        }
        public List<PropertyInfo> GetAssociationProperties(Type entityType)
        {
            return GetProperties(entityType, x => x.Association != null && x.Association.IsMany && x.Association.ThisKeyIsPrimaryKey);
        }
        
        
        #endregion
    }
}
